use common::utils::string_utils;
use semver::Version;

use std::mem::MaybeUninit;
use std::sync::{Arc, Mutex};
use tokio::sync::oneshot;
use tracing::info;

use crate::airport::airport::Airport;

use crate::db::mysql::MySQLPool;
use crate::file::file_manager::FileManager;
use crate::log;
use crate::net::http_net::HttpNet;
use crate::net::tcp_net::TCPNet;
use crate::net::xprc_event_handler::XRPCEventHandler;
use crate::protocol::protocol_v1::ProtocolV1Handler;
use common::base::config::Config;

pub static mut APP: MaybeUninit<Application> = MaybeUninit::uninit();

pub struct Application<'a> {
    // 线程安全问题
    exit_sender: Mutex<Option<oneshot::Sender<()>>>,
    //
    exit_reciver: Option<oneshot::Receiver<()>>,
    //
    conn_id: i64,
    // 消息中心
    airport: Arc<Box<Airport>>,
    //
    config: Arc<Box<Config>>,
    //
    file_manager: Arc<Box<FileManager>>,
    //
    pub mysql_pool: Option<Box<MySQLPool<'a>>>,
}

impl Application<'_> {
    //
    pub fn get_airport() -> Arc<Box<Airport>> {
        unsafe { APP.assume_init_ref().airport.clone() }
    }
    //
    pub fn get_config() -> Arc<Box<Config>> {
        unsafe { APP.assume_init_ref().config.clone() }
    }
    /**
     * 获取文件管理者
     */
    pub fn get_file_manager() -> Arc<Box<FileManager>> {
        unsafe { APP.assume_init_ref().file_manager.clone() }
    }
    pub fn get_conn_id() -> i64 {
        unsafe { APP.assume_init_ref().conn_id }
    }
    //
    pub fn set_conn_id(conn_id: i64) {
        unsafe { APP.assume_init_mut().conn_id = conn_id }
    }

    /**
     * 加载 airport
     */
    async fn load_airport(config: &Box<Config>) -> Arc<Box<Airport>> {
        let xrpc_event_handler = XRPCEventHandler::new(config);

        let mut xrpc_net = Box::new(TCPNet::new(xrpc_event_handler));

        let xrpc_port = config.get_i32("xport", "xrpc-port").unwrap_or(8090) as u16;

        let xrpc_ip = config.get_str("xport", "xrpc-ip").unwrap_or("0.0.0.0");

        xrpc_net.init(String::from(xrpc_ip), xrpc_port);

        let xrpc_net = Arc::new(xrpc_net);

        let mut http_net = Box::new(HttpNet::new());

        let http_port = config.get_i32("xport", "http-port").unwrap_or(8091) as u16;

        let http_ip = config.get_str("xport", "http-ip").unwrap_or("0.0.0.0");

        http_net.init(String::from(http_ip), http_port);

        let http_net = Arc::new(http_net);

        let clone_xrpc_net = xrpc_net.clone();

        let clone_http_net = http_net.clone();

        let mut airport = Airport::new(xrpc_net, http_net);

        let v1_hanlder = Box::new(ProtocolV1Handler::new());

        airport.add_protocol_handler(v1_hanlder);

        let (xprc_sender, xprc_receicer) = oneshot::channel::<bool>();

        let (http_sender, http_receicer) = oneshot::channel::<bool>();

        tokio::spawn(async move {
            clone_xrpc_net.start(xprc_sender).await;
        });

        tokio::spawn(async move {
            clone_http_net.start(http_sender).await;
        });

        let is_succeed = xprc_receicer.await;

        let is_succeed = is_succeed.expect("启动 xprc 失败");

        if !is_succeed {
            panic!("启动 xprc 失败");
        }

        let is_succeed = http_receicer.await;

        let is_succeed = is_succeed.expect("启动 http 服务失败");

        if !is_succeed {
            panic!("启动 http 服务失败");
        }

        Arc::new(airport)
    }
    /**
     * 加载文件管理
     */
    pub fn load_file_manager(config: &Box<Config>) -> Arc<Box<FileManager>> {
        let file_manager = Arc::new(Box::new(FileManager::new(config)));

        let clone_file_manager = file_manager.clone();

        tokio::spawn(async move {
            let _ = clone_file_manager.check_and_delete_expire_info();
        });

        file_manager.clone()
    }

    pub async fn load_default_services(config: Arc<Box<Config>>) {
        let default_dxc = config.get_str_array("xport", "default-dxc");

        let dxc_manager = Self::get_airport().get_dxc_manager();

        for dxc_name in default_dxc {
            let service_name = config.get_str(dxc_name, "service-name");

            if service_name.is_none() {
                panic!("加载 dxc {} 失败， 缺少 service-name 属性", dxc_name);
            }

            let service_name = service_name.unwrap();

            let config = Application::get_config();

            let config = config.get_table(dxc_name).unwrap().to_string();

            let dxc_version = string_utils::extract_version(&dxc_name);

            if dxc_version.is_none() {
                panic!("加载 dxc {} 失败， 版本号解析错误", dxc_name);
            }

            let dxc_version = dxc_version.unwrap();

            let dxc_name = dxc_name.replace(&dxc_version, "").replace("_", "");

            let dxc_version = dxc_version.replace("_", ".");

            let dxc_version = Version::parse(&dxc_version);

            if dxc_version.is_err() {
                panic!("加载 dxc {} 失败， 版本号解析错误", dxc_name);
            }

            let dxc_version = dxc_version.unwrap();

            dxc_manager
                .load_local_dxc(&dxc_name, &dxc_version, service_name, &config)
                .await
                .expect("加载默认服务失败！");
        }
    }

    /**
     * 初始化
     */
    pub async fn init() {
        let (sender, receiver) = oneshot::channel::<()>();
        let config = Config::load("dxmesh.toml").await;
        let config = Box::new(config);
        // 初始化日志
        log::init(&config);

        let mut mysql_pool: Option<Box<MySQLPool>> = None;

        let dbs = config.get_str_array("xport", "db");

        if dbs.contains(&"mysql") {
            mysql_pool = Some(Box::new(MySQLPool::new(&config).await));
        }

        info!("启动文件管理器...");
        let file_manager = Self::load_file_manager(&config);
        info!("启动 Airport...");
        let airport = Self::load_airport(&config).await;

        let config = Arc::new(config);

        unsafe {
            APP.as_mut_ptr().write(Application {
                airport,
                conn_id: 0,
                mysql_pool,
                exit_sender: Mutex::new(Some(sender)),
                exit_reciver: Some(receiver),
                config: config.clone(),
                file_manager,
            });
        }

        Self::load_default_services(config).await;
    }
    /**
     *
     */
    pub fn exit() {
        unsafe {
            // 方式多次调用
            let app_ins = APP.assume_init_ref();
            let mut sender = app_ins.exit_sender.lock().unwrap();
            if let Some(sender) = sender.take() {
                let _ = sender.send(());
            }
        }
    }
    /**
     * 全局只执行一次，不需要加锁
     */
    pub async fn run_loop() {
        unsafe {
            let app_ins = APP.assume_init_mut();

            if let Some(receiver) = app_ins.exit_reciver.take() {
                receiver.await.unwrap();
            }
        }
    }
}
